home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Stuart's Tech Notes / Stu’sThreadUtils / test.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-19  |  5.3 KB  |  188 lines  |  [TEXT/KAHL]

  1. // test.c
  2. //
  3. // Copyright (C) 6th March 1994  Stuart Cheshire <cheshire@cs.stanford.edu>
  4. //
  5. // The program contains three tests of the Stu’s thread utils.
  6.  
  7. #include <stdio.h>
  8. #include "ThreadSynch.h"
  9. #include "PipeLine.h"
  10.  
  11. // *************************************************************************
  12. // Test of pipeline routines
  13. //
  14. // This test has a number of producers concurrently writing into a single
  15. // pipeline, and multiple consumers concurrently reading out of that
  16. // pipeline and printing onto the console window.
  17.  
  18. #define BUFFER_SIZE 4
  19. #define NUM_PRODUCERS 7
  20. #define NUM_CONSUMERS 6
  21. static const char message[] = "Hello world";
  22.  
  23. static unsigned char buffer[BUFFER_SIZE];
  24. static PipeLine pipe;
  25. static Semaphore threadwait;    // to wait for all threads to finish
  26.  
  27. static pascal void *producer(void *unused)
  28.     {
  29.     const char *ptr = message;
  30.     while (*ptr) PipeLinePutData(&pipe, *ptr++);
  31.     PipeLineClose(&pipe);
  32.     return(NULL);
  33.     }
  34.  
  35. static pascal void *consumer(void *unused)
  36.     {
  37.     int c;
  38.     while ((c = PipeLineGetData(&pipe)) != NO_WRITERS) { putchar(c); fflush(stdout); }
  39.     SemaphoreV(&threadwait);    // Signal that thread has finished
  40.     return(NULL);
  41.     }
  42.  
  43. static void pipetest(void)
  44.     {
  45.     int i;
  46.     PipeLineInit(&pipe, buffer, sizeof(buffer));
  47.     SemaphoreInit(&threadwait, 0);
  48.     
  49.     // Create a bunch of preemptive threads writing into the pipe
  50.     for (i=0; i<NUM_PRODUCERS; i++)
  51.         {
  52.         PipeLineOpen(&pipe);
  53.         if (NewThread(kPreemptiveThread, &producer, NULL, 0, 0, NULL, NULL) != noErr)
  54.             ExitToShell();
  55.         }
  56.  
  57.     // Create a bunch of cooperative threads reading from the pipe
  58.     for (i=0; i<NUM_CONSUMERS; i++)
  59.         if (NewThread(kCooperativeThread, &consumer, NULL, 0, 0, NULL, NULL) != noErr)
  60.             ExitToShell();
  61.  
  62.     // Wait for all the readers to terminate
  63.     for (i=0; i<NUM_CONSUMERS; i++) SemaphoreP(&threadwait);
  64.     }
  65.  
  66. // *************************************************************************
  67. // Test of Locks and Condition Variables
  68. //
  69. // This test models a country bridge, which is only wide enough to carry
  70. // cars in one direction at a time, and only strong enough to carry three
  71. // cars at a time. 25 cars arrive from each direction and have to wait until
  72. // the conditions are safe for them to cross the bridge. It is a lightly
  73. // travelled rural bridge, so enforcing strict queueing and fairness is not
  74. // necessary. Simplicity and elegance of the code is more important.
  75.  
  76. #define NUM_CARS 25
  77.  
  78. static MutexLock lock;
  79. static ConditionVar cond;
  80. static int cars[2];
  81.  
  82. static void ArriveBridge(short direc)
  83.     {
  84.     short other_direction = 1 - direc;
  85.     MutexLockAcquire(&lock);
  86.     while (cars[direc] >= 3 || cars[other_direction] > 0) ConditionVarWait(&cond);
  87.     cars[direc]++;
  88.     if (direc) printf("            <-XXX\n"); else printf("XXX->\n");
  89.     MutexLockRelease(&lock);
  90.     YieldToAnyThread();        // Yield time while we drive onto bridge
  91.     }
  92.  
  93. static void CrossBridge(short direc)
  94.     {
  95.     if (direc) printf("      <-XXX\n"); else printf("      XXX->\n");
  96.     YieldToAnyThread();        // Yield time while we trundle over bridge
  97.     }
  98.  
  99. static void ExitBridge(short direc)
  100.     {
  101.     YieldToAnyThread();        // Yield time while we drive off bridge
  102.     MutexLockAcquire(&lock);
  103.     if (direc) printf("<-XXX\n"); else printf("            XXX->\n");
  104.     cars[direc]--;
  105.     ConditionVarBroadcast(&cond);
  106.     MutexLockRelease(&lock);
  107.     }
  108.  
  109. static pascal void *OneVehicle(void *direc)
  110.     {
  111.     ArriveBridge((short)direc);
  112.     CrossBridge((short)direc);
  113.     ExitBridge((short)direc);
  114.     SemaphoreV(&threadwait);    // Signal that thread has finished
  115.     }
  116.  
  117. static pascal void *make_cars(void *direc)
  118.     {
  119.     int i,j;
  120.     for (i=0; i<NUM_CARS; i++)
  121.         {
  122.         if (NewThread(kCooperativeThread, &OneVehicle, direc, 0, 0, NULL, NULL) != noErr)
  123.             ExitToShell();
  124.         for (j=0; j<5; j++) YieldToAnyThread();
  125.         }
  126.     }
  127.  
  128. static void condtest(void)
  129.     {
  130.     int i;
  131.     MutexLockInit(&lock);
  132.     ConditionVarInit(&cond, &lock);
  133.     if (NewThread(kCooperativeThread, &make_cars, (void*)0, 0, 0, NULL, NULL) != noErr)
  134.             ExitToShell();
  135.     if (NewThread(kCooperativeThread, &make_cars, (void*)1, 0, 0, NULL, NULL) != noErr)
  136.             ExitToShell();
  137.     for (i=0; i<NUM_CARS*2; i++) SemaphoreP(&threadwait);
  138.     }
  139.  
  140. // *************************************************************************
  141. // Thread Manager speed test
  142. //
  143. // How long does it take your Mac to context switch from one thread to another?
  144. // My Quadra 700 averages about 100us (microseconds) which is pretty good
  145. // even compared to threads packages on high-end workstations.
  146.  
  147. #define SPEED_TESTS 5000
  148. Semaphore speed1, speed2;
  149.  
  150. static pascal void *speedthread(void *unused)
  151.     {
  152.     int i;
  153.     for (i=0; i<SPEED_TESTS; i++) { SemaphoreV(&speed1); SemaphoreP(&speed2); }
  154.     }
  155.  
  156. static void speedtest(void)
  157.     {
  158.     int i;
  159.     long time1, time;
  160.     SemaphoreInit(&speed1, 0);
  161.     SemaphoreInit(&speed2, 0);
  162.     if (NewThread(kCooperativeThread, &speedthread, NULL, 0, kFPUNotNeeded, NULL, NULL) != noErr)
  163.         ExitToShell();
  164.     time1 = TickCount();
  165.     for (i=0; i<SPEED_TESTS; i++) { SemaphoreP(&speed1); SemaphoreV(&speed2); }
  166.     time = TickCount() - time1;
  167.     printf("%d context switches took %ld.%03ld seconds\n",
  168.         SPEED_TESTS*2, time/60, (time%60) * 16);
  169.     }
  170.  
  171. // *************************************************************************
  172. // main. It all starts here.
  173.  
  174. main()
  175.     {
  176.     // Call printf first to make sure ANSI segment gets loaded
  177.     printf("Thread synchronization tests\n");
  178.  
  179.     printf("Pipeline test\n\n");
  180.     pipetest();
  181.  
  182.     printf("\n\nCountry Bridge test\n\n");
  183.     condtest();
  184.  
  185.     printf("\n\nContext switch speed test\n\n");
  186.     speedtest();
  187.     }
  188.